package com.sikaryofficial.backend.manager;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sikaryofficial.backend.config.PointsRuleConfig;
import com.sikaryofficial.backend.constant.ArticleLabelEnum;
import com.sikaryofficial.backend.constant.GuideTaskEnum;
import com.sikaryofficial.backend.constant.MyStatisticsTypeEnum;
import com.sikaryofficial.backend.constant.TagStatus;
import com.sikaryofficial.backend.constant.UserActionTypeEnum;
import com.sikaryofficial.backend.domain.dto.req.UserActionListReq;
import com.sikaryofficial.backend.domain.dto.req.UserActionReq;
import com.sikaryofficial.backend.domain.dto.req.points.GuideTaskReq;
import com.sikaryofficial.backend.domain.dto.resp.UserActionListResp;
import com.sikaryofficial.backend.domain.entity.ArticleExt;
import com.sikaryofficial.backend.domain.entity.ArticleTag;
import com.sikaryofficial.backend.domain.entity.UserAction;
import com.sikaryofficial.backend.service.IArticleExtService;
import com.sikaryofficial.backend.service.IArticleTagService;
import com.sikaryofficial.backend.service.IPointsDetailStrategy;
import com.sikaryofficial.backend.service.IUserActionService;
import com.sikaryofficial.backend.service.IUserActionStrategy;
import com.sikaryofficial.backend.service.article.cache.ArticleActionCacheService;
import com.sikaryofficial.backend.service.guidetask.GuideTaskProcess;
import com.sikaryofficial.backend.service.points.cache.PointsRuleConfigCacheService;
import com.sikaryofficial.backend.service.statistics.MyStatisticsEvent;
import com.sikaryofficial.common.core.constant.PointRuleConstant;
import com.sikaryofficial.common.core.domain.R;
import com.sikaryofficial.common.core.exception.ServiceException;
import com.sikaryofficial.common.security.utils.SecurityUtils;
import com.sikaryofficial.system.api.RemoteArticleService;
import com.sikaryofficial.system.api.model.UserPointResultVO;
import com.sikaryofficial.system.api.model.infomation.ArticleDTO;
import com.sikaryofficial.system.api.model.infomation.TopicObjVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author : qinjinyuan
 * @desc : 活动管理服务
 * @date : 2023/10/30 15:39
 */
@Service
@Slf4j
@SuppressWarnings(value="unchecked")
public class UserActionManager {
    @Resource
    private Map<String, IUserActionStrategy> userActionStrategyMap;
    @Autowired
    private IUserActionService userActionService;
    @Resource
    private Map<String, IPointsDetailStrategy> pointsDetailStrategyMap;
    @Autowired
    private GuideTaskProcess guideTaskProcess;
    @Autowired
    private RemoteArticleService remoteArticleService;
    @Autowired
    private IArticleExtService articleExtService;
    @Autowired
    private IArticleTagService articleTagService;
    @Autowired
    private ArticleActionCacheService articleActionCacheService;
    @Resource
    private PointsRuleConfigCacheService ruleConfigCacheService;
    @Resource
    private PointsRuleConfig pointsRuleConfig;

    @Transactional(rollbackFor = Exception.class)
    public UserPointResultVO userActionSave(UserActionReq req) {
        Long userId = SecurityUtils.getUserId();
        IUserActionStrategy userActionStrategy = userActionStrategyMap.get(UserActionTypeEnum.getByCode(req.getActionType()).getServiceName() + IUserActionStrategy.SUFFIX);
        if (Objects.isNull(userActionStrategy)) {
            throw new ServiceException("action type is error.");
        }
        if (Objects.isNull(req.getObjectId())) {
            throw new ServiceException("object id is empty.");
        }
        // 1、数据检查
        userActionStrategy.before(req);
        // 2、保存 点赞 | 收藏 | 转发 数据
        userActionStrategy.updateUserAction(req);
        // 3、处理  点赞 | 收藏 | 转发 个人统计数据
        userActionStrategy.processMyStatisticsEvent(
                new MyStatisticsEvent(Objects.requireNonNull(MyStatisticsTypeEnum.getEnum(req.getBusinessType())).getBusinessType(),
                        userId,
                        req.getObjectId()),
                req.isOptions());
        // 4、缓存数据处理
        userActionStrategy.after(MyStatisticsTypeEnum.getEnum(req.getBusinessType()), req.getObjectId(), req.isOptions(), userId);
        // 5、转发或者点赞积分处理
        UserPointResultVO pointResultVO = UserPointResultVO.builder().getPointsFlag(false).pointsDetailValue(0).build();
        pointsProcess(req, userId, UserActionTypeEnum.getServicePrefixCode(req.getActionType(), req.getBusinessType()), pointResultVO);
        // 6、收到的点赞积分处理
        processArticleReceivedLike(req, req.getAuthorId(), pointResultVO);
        // 7、对于转发的指引任务处理
        pointsGuideTaskProcess(req, userId);
        return pointResultVO;
    }

    private void pointsProcess(UserActionReq req, Long userId, String servicePrefix,
                               UserPointResultVO pointResultVO) {
        if (Boolean.TRUE.equals(req.isOptions())
                || CharSequenceUtil.isBlank(servicePrefix)
                || Objects.isNull(userId)) {
            log.info("参数错误==================");
            return;
        }
        // 1、点赞积分处理
        IPointsDetailStrategy pointsDetailStrategy = pointsDetailStrategyMap.get(servicePrefix + IPointsDetailStrategy.SUFFIX);
        if (Objects.isNull(pointsDetailStrategy)) {
            log.info("pointsDetailStrategy===空对象===============");
            return;
        }
        // 下面的 3中场景的点赞积分处理 【如果3中规则同时生效，都可以获取积分】
        boolean hasReceivedLike = PointRuleConstant.ARTICLE_LIKE.equals(servicePrefix)
                && MyStatisticsTypeEnum.LIKES_ARTICLE.getBusinessType().equals(req.getBusinessType());
        if (Boolean.FALSE.equals(hasReceivedLike)) {
            return;
        }
        // 普通点赞
        boolean flag = pointsDetailStrategy.updatePoints(req.getObjectId(), userId);
        if (Boolean.TRUE.equals(flag)) {
            pointResultVO.setGetPointsFlag(true);
            pointResultVO.setPointsDetailValue(ruleConfigCacheService.getConfigByCode(PointRuleConstant.ARTICLE_LIKE).getPointsValue());
        }
        // 点赞带特定Topic的Post
        processLikeWithTopic(req, userId, pointResultVO);
        // 浏览并点赞官方发布的带Topic的Post
        processViewAndLikeEvent(req, userId, pointResultVO);
    }

    private void processArticleReceivedLike(UserActionReq req, Long userId, UserPointResultVO pointResultVO) {
        UserActionTypeEnum userActionTypeEnum = UserActionTypeEnum.getByCode(req.getActionType());
        boolean hasReceivedLike = UserActionTypeEnum.LIKES == userActionTypeEnum && MyStatisticsTypeEnum.LIKES_ARTICLE.getBusinessType().equals(req.getBusinessType());
        if (Boolean.FALSE.equals(hasReceivedLike)) {
            return;
        }
        // 1、点赞积分处理
        IPointsDetailStrategy pointsDetailStrategy = pointsDetailStrategyMap.get(PointRuleConstant.ARTICLE_RECEIVED_LIKE + IPointsDetailStrategy.SUFFIX);
        if (Objects.isNull(pointsDetailStrategy)) {
            log.info("pointsDetailStrategy===空对象===============");
            return;
        }
        boolean flag = pointsDetailStrategy.updatePoints(req.getObjectId(), userId);
        if (Boolean.TRUE.equals(flag)) {
            pointResultVO.setGetPointsFlag(true);
            pointResultVO.setPointsDetailValue(ruleConfigCacheService.getConfigByCode(PointRuleConstant.ARTICLE_LIKE).getPointsValue());
        }
    }

    private void processLikeWithTopic(UserActionReq req, Long userId, UserPointResultVO data) {
        Integer count = getTopicNumber(getArticleExtInfo(req.getObjectId()));
        boolean isBackend = Objects.nonNull(count) && count > 0;
        if (isBackend) {
            IPointsDetailStrategy pointsDetailStrategy = pointsDetailStrategyMap.get(PointRuleConstant.ARTICLE_LIKE_WITH_TOPIC + IPointsDetailStrategy.SUFFIX);
            boolean pointResult = pointsDetailStrategy.updatePoints(req.getObjectId(), userId);
            if (Boolean.TRUE.equals(pointResult)) {
                data.setPointsDetailValue(ruleConfigCacheService.getConfigByCode(PointRuleConstant.ARTICLE_LIKE_WITH_TOPIC).getPointsValue());
                data.setGetPointsFlag(true);
            }
        }
    }

    private void processViewAndLikeEvent(UserActionReq req, Long userId, UserPointResultVO data) {
        R<ArticleDTO> result = remoteArticleService.getInfo(req.getObjectId());
        if (Objects.isNull(result) || Objects.isNull(result.getData())) {
            log.error("Article is not exist.");
            return;
        }
        ArticleDTO articleDTO = result.getData();
        // 浏览并点赞官方发布的带Event字样的帖子
        log.info("processViewAndLikeEvent===getCreatedBy= {} , getArticleLabel = {} ", articleDTO.getCreatedBy(), articleDTO.getArticleLabel());
        boolean hasEventArticle = pointsRuleConfig.isOfficialUser(articleDTO.getCreatedBy())
                && Objects.equals(ArticleLabelEnum.EVENT.getCode(), articleDTO.getArticleLabel())
                && articleActionCacheService.hasUserViewed(userId, req.getObjectId())
                && articleActionCacheService.hasNoUserLiked(userId, req.getObjectId());
        articleActionCacheService.recordUserLike(userId, req.getObjectId());
        if (hasEventArticle) {
            IPointsDetailStrategy pointsDetailStrategy = pointsDetailStrategyMap.get(PointRuleConstant.ARTICLE_VIEW_LIKE + IPointsDetailStrategy.SUFFIX);
            boolean pointResult = pointsDetailStrategy.updatePoints(req.getObjectId(), userId);
            articleActionCacheService.clearUserViewLikeCache(userId, req.getObjectId());
            if (Boolean.TRUE.equals(pointResult)) {
                data.setPointsDetailValue(ruleConfigCacheService.getConfigByCode(PointRuleConstant.ARTICLE_VIEW_LIKE).getPointsValue());
                data.setGetPointsFlag(true);
            }
        }
    }

    private Integer getTopicNumber(List<TopicObjVO> topicList) {
        Integer count = 0;
        if (CollUtil.isNotEmpty(topicList)) {
            count = articleTagService.lambdaQuery()
                    .in(ArticleTag::getArticleId, topicList.stream().map(TopicObjVO::getTopicId).collect(Collectors.toList()))
                    .eq(ArticleTag::getTagEnable, TagStatus.ENABLED.getCode())
                    .eq(ArticleTag::getDeletedVersion, 0L)
                    .count();
        }
        return count;
    }

    private List<TopicObjVO> getArticleExtInfo(Long articleId) {
        ArticleExt articleExt = articleExtService.getVOById(articleId);
        return Optional.ofNullable(articleExt)
                .map(ArticleExt::getTopicList)
                .orElse(Lists.newArrayList());
    }

    private void pointsGuideTaskProcess(UserActionReq req, Long userId) {
        if (Objects.nonNull(req.getHasGuideTask())
                && Boolean.TRUE.equals(req.getHasGuideTask())
                && UserActionTypeEnum.FORWARD.getCode().equals(req.getActionType())) {
            GuideTaskReq guideTaskReq = new GuideTaskReq();
            guideTaskReq.setUserId(userId);
            guideTaskReq.setTaskCode(GuideTaskEnum.SHARE_FRIEND.getTaskCode());
            guideTaskProcess.processGuideTask(guideTaskReq);
        }
    }

    /**
     * 分页查询用户行为
     *
     * @param req
     * @return
     */
    public IPage<? extends UserActionListResp> listPage(UserActionListReq req) {
        UserActionTypeEnum actionType = UserActionTypeEnum.getByCode(req.getActionType());
        if (Objects.isNull(actionType)) {
            throw new ServiceException("action type is error.");
        }
        MyStatisticsTypeEnum myStatisticsTypeEnum = MyStatisticsTypeEnum.getEnum(req.getBusinessType());
        if (Objects.isNull(myStatisticsTypeEnum)) {
            throw new ServiceException("business type is error.");
        }
        // 查询用户行为 （点赞，分享，评论）
        Page<UserAction> customerPage = new Page<>(req.getPageNum(), req.getPageSize());
        IPage<UserAction> userActionPage = userActionService.page(customerPage, new LambdaQueryWrapper<UserAction>()
                .eq(UserAction::getActionType, actionType.getCode())
                .eq(UserAction::getBusinessType, myStatisticsTypeEnum.getBusinessType())
                .eq(UserAction::getDeletedVersion, 0L)
                .eq(UserAction::getCreatedBy, SecurityUtils.getUserId())
                .orderByDesc(UserAction::getCreatedTime)
        );
        if (Objects.isNull(userActionPage) || CollUtil.isEmpty(userActionPage.getRecords())) {
            return new Page<>(req.getPageNum(), req.getPageSize(), 0);
        }
        IUserActionStrategy userActionStrategy = userActionStrategyMap.get(UserActionTypeEnum.getByCode(req.getActionType()).getServiceName() + IUserActionStrategy.SUFFIX);
        return userActionStrategy.buildObjByActionType(userActionPage, myStatisticsTypeEnum);
    }
}
